package com.supermarket.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.supermarket.entity.Article;
import com.supermarket.entity.ArticleMedia;
import com.supermarket.entity.DTO.ArticleDTO;
import com.supermarket.entity.User;
import com.supermarket.exception.ArticleException;
import com.supermarket.mapper.ArticleMapper;
import com.supermarket.mapper.ArticleMediaMapper;
import com.supermarket.mapper.ArticleCommentMapper;
import com.supermarket.mapper.UserMapper;
import com.supermarket.common.RedisUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import cn.hutool.core.util.StrUtil;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ArticleService {

    @Resource
    private ArticleMapper articleMapper;

    @Resource
    private ArticleMediaMapper articleMediaMapper;

    @Resource
    private ArticleCommentMapper articleCommentMapper;

    @Resource
    private UserMapper userMapper;
    
    @Resource
    private ArticleLikeService articleLikeService;
    
    @Resource
    private ArticleCommentService articleCommentService;
    
    @Resource
    private RedisUtil redisUtil;
    
    // Redis缓存相关的Key前缀
    private static final String ARTICLE_DETAIL_KEY = "article:detail:";
    private static final String ARTICLE_USER_KEY = "article:user:";
    private static final String ARTICLE_LIST_KEY = "article:list";
    private static final String ARTICLE_HOT_KEY = "article:hot";
    private static final String ARTICLE_STATUS_KEY = "article:status:";
    private static final String ARTICLE_BATCH_KEY = "article:batch:";
    private static final int ARTICLE_CACHE_SECONDS = 21600; // 文章缓存默认6小时
    private static final int ARTICLE_LIST_CACHE_SECONDS = 1800; // 列表缓存30分钟
    private static final int ARTICLE_HOT_CACHE_SECONDS = 3600; // 热门文章缓存1小时

    // 媒体文件存储路径
    private static final String UPLOAD_DIR = "uploads/article/";

    /**
     * 发布文章
     *
     * @param article     文章对象
     * @param mediaFiles  媒体文件列表
     * @param mediaTypes  媒体类型列表
     * @return 发布的文章ID
     */
    @Transactional
    public Integer publishArticle(Article article, List<MultipartFile> mediaFiles, List<String> mediaTypes) throws IOException {
        // 验证文章内容
        if (StrUtil.isBlank(article.getContent())) {
            throw new ArticleException("文章内容不能为空");
        }

        // 设置默认状态为已发布
        if (article.getStatus() == null) {
            article.setStatus("PUBLISHED");
        }

        // 插入文章
        articleMapper.insertArticle(article);
        Integer articleId = article.getId();

        // 处理媒体文件
        if (mediaFiles != null && !mediaFiles.isEmpty()) {
            processMediaFiles(articleId, mediaFiles, mediaTypes);
        }
        
        // 清除文章列表缓存
        clearArticleListCache();
        // 清除用户文章列表缓存
        redisUtil.delete(ARTICLE_USER_KEY + article.getUserId());
        // 清除文章状态分类缓存
        redisUtil.delete(ARTICLE_STATUS_KEY + article.getStatus());

        return articleId;
    }

    /**
     * 处理媒体文件上传
     *
     * @param articleId   文章ID
     * @param mediaFiles  媒体文件列表
     * @param mediaTypes  媒体类型列表
     * @throws IOException 文件处理异常
     */
    private void processMediaFiles(Integer articleId, List<MultipartFile> mediaFiles, List<String> mediaTypes) throws IOException {
        // 确保上传目录存在
        Path uploadPath = Paths.get(UPLOAD_DIR);
        if (!Files.exists(uploadPath)) {
            Files.createDirectories(uploadPath);
        }

        List<ArticleMedia> mediaList = new ArrayList<>();
        
        for (int i = 0; i < mediaFiles.size(); i++) {
            MultipartFile file = mediaFiles.get(i);
            String mediaType = (mediaTypes != null && i < mediaTypes.size()) ? mediaTypes.get(i) : "IMAGE";
            
            if (!file.isEmpty()) {
                // 生成唯一文件名
                String originalFilename = file.getOriginalFilename();
                String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
                String filename = UUID.randomUUID() + fileExtension;
                
                // 保存文件
                Path filePath = uploadPath.resolve(filename);
                Files.copy(file.getInputStream(), filePath);
                
                // 创建媒体记录
                ArticleMedia media = new ArticleMedia();
                media.setArticleId(articleId);
                media.setMediaType(mediaType);
                media.setMediaUrl(UPLOAD_DIR + filename);
                media.setSortOrder(i);
                
                mediaList.add(media);
            }
        }
        
        // 批量插入媒体记录
        if (!mediaList.isEmpty()) {
            articleMediaMapper.batchInsertArticleMedia(mediaList);
        }
    }

    /**
     * 更新文章内容
     *
     * @param article 文章对象
     * @return 影响的行数
     */
    @Transactional
    public int updateArticle(Article article) {
        if (article.getId() == null) {
            throw new ArticleException("文章ID不能为空");
        }
        
        // 检查文章是否存在
        Article existingArticle = articleMapper.selectArticleById(article.getId());
        if (existingArticle == null) {
            throw new ArticleException("文章不存在");
        }
        
        int result = articleMapper.updateArticle(article);
        
        if (result > 0) {
            // 更新缓存
            clearArticleCache(article.getId(), article.getUserId());
        }
        
        return result;
    }

    /**
     * 更新文章内容及其媒体文件
     *
     * @param article        文章对象
     * @param deleteMediaIds 要删除的媒体ID列表
     * @param mediaFiles     新增的媒体文件列表
     * @param mediaTypes     新增的媒体类型列表
     * @return 是否更新成功
     * @throws IOException 文件处理异常
     */
    @Transactional
    public boolean updateArticleWithMedia(Article article, List<Integer> deleteMediaIds, List<MultipartFile> mediaFiles, List<String> mediaTypes) throws IOException {
        if (article.getId() == null) {
            throw new ArticleException("文章ID不能为空");
        }
        
        // 检查文章是否存在
        Article existingArticle = articleMapper.selectArticleById(article.getId());
        if (existingArticle == null) {
            throw new ArticleException("文章不存在");
        }
        
        // 更新文章基本信息
        int result = articleMapper.updateArticle(article);
        if (result <= 0) {
            return false;
        }
        
        // 删除指定的媒体文件
        if (deleteMediaIds != null && !deleteMediaIds.isEmpty()) {
            for (Integer mediaId : deleteMediaIds) {
                // 获取媒体信息以便删除文件
                ArticleMedia media = articleMediaMapper.selectArticleMediaById(mediaId);
                if (media != null) {
                    // 删除物理文件
                    if (media.getMediaUrl() != null && !media.getMediaUrl().isEmpty()) {
                        try {
                            Path filePath = Paths.get(media.getMediaUrl());
                            Files.deleteIfExists(filePath);
                        } catch (IOException e) {
                            // 记录错误但继续处理
                            System.err.println("删除文件失败: " + e.getMessage());
                        }
                    }
                    // 删除数据库记录
                    articleMediaMapper.deleteArticleMedia(mediaId);
                }
            }
        }
        
        // 添加新的媒体文件
        if (mediaFiles != null && !mediaFiles.isEmpty()) {
            processMediaFiles(article.getId(), mediaFiles, mediaTypes);
        }
        
        // 清除缓存
        clearArticleCache(article.getId(), existingArticle.getUserId());
        
        return true;
    }

    /**
     * 删除文章
     *
     * @param id 文章ID
     * @return 影响的行数
     */
    @Transactional
    public int deleteArticle(Integer id) {
        // 获取文章信息以便删除缓存
        Article article = articleMapper.selectArticleById(id);
        if (article == null) {
            throw new ArticleException("文章不存在");
        }
        
        // 先删除关联的媒体文件记录
        List<ArticleMedia> mediaList = articleMediaMapper.selectMediaByArticleId(id);
        for (ArticleMedia media : mediaList) {
            // 删除物理文件
            if (media.getMediaUrl() != null && !media.getMediaUrl().isEmpty()) {
                try {
                    Path filePath = Paths.get(media.getMediaUrl());
                    Files.deleteIfExists(filePath);
                } catch (IOException e) {
                    // 记录错误但继续处理
                    System.err.println("删除文件失败: " + e.getMessage());
                }
            }
        }
        // 删除媒体记录
        articleMediaMapper.deleteMediaByArticleId(id);
        
        // 删除文章评论
        articleCommentMapper.deleteCommentsByArticleId(id);
        
        // 删除文章
        int result = articleMapper.deleteArticle(id);
        
        if (result > 0) {
            // 清除缓存
            clearArticleCache(id, article.getUserId());
        }
        
        return result;
    }

    /**
     * 获取文章详情
     *
     * @param id 文章ID
     * @return 文章DTO对象
     */
    public ArticleDTO getArticleDetail(Integer id) {
        // 尝试从缓存获取
        String cacheKey = ARTICLE_DETAIL_KEY + id;
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (ArticleDTO) cached;
        }
        
        // 缓存未命中，查询数据库
        Article article = articleMapper.selectArticleById(id);
        if (article == null) {
            return null;
        }

        // 递增文章热度
        incrementArticleHot(id);
        
        // 构建文章DTO
        ArticleDTO articleDTO = buildArticleVO(article);
        
        // 将结果存入缓存
        redisUtil.set(cacheKey, articleDTO, ARTICLE_CACHE_SECONDS);
        
        return articleDTO;
    }

    /**
     * 批量获取文章详情
     *
     * @param ids 文章ID列表
     * @return 文章ID与其详情的映射
     */
    public Map<Integer, ArticleDTO> getBatchArticleDetails(List<Integer> ids) {
        if (ids == null || ids.isEmpty()) {
            return new HashMap<>();
        }
        
        // 构建缓存键
        String idStr = ids.stream()
                .sorted()
                .map(String::valueOf)
                .collect(Collectors.joining("-"));
        String cacheKey = ARTICLE_BATCH_KEY + idStr.hashCode();
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (Map<Integer, ArticleDTO>) cached;
        }
        
        // 缓存未命中，查询数据库
        Map<Integer, ArticleDTO> result = new HashMap<>();
        
        // 查询所有文章
        List<Article> articles = articleMapper.selectArticlesByIds(ids);
        if (articles == null || articles.isEmpty()) {
            return result;
        }
        
        // 预先批量获取所有文章的评论数
        // 这样可以避免为每篇文章单独查询评论数
        Map<Integer, Integer> commentCountsMap = articleCommentService.getBatchArticleCommentCounts(ids);
        
        // 构建每篇文章的DTO
        for (Article article : articles) {
            ArticleDTO dto = new ArticleDTO();
            dto.setId(article.getId());
            dto.setContent(article.getContent());
            dto.setStatus(article.getStatus());
            dto.setViews(article.getViews());
            dto.setLikes(article.getLikes());
            dto.setCreateTime(article.getCreateTime());
            dto.setUpdateTime(article.getUpdateTime());
            
            // 获取用户信息
            User user = userMapper.selectUserById(article.getUserId());
            if (user != null) {
                dto.setAuthor(user);
            }
            
            // 获取文章媒体列表
            List<ArticleMedia> mediaList = articleMediaMapper.selectMediaByArticleId(article.getId());
            dto.setMediaList(mediaList);
            
            // 设置评论数量 - 从批量获取的映射中获取
            Integer commentCount = commentCountsMap.getOrDefault(article.getId(), 0);
            dto.setCommentCount(commentCount);
            
            result.put(article.getId(), dto);
        }
        
        // 将结果存入缓存
        if (!result.isEmpty()) {
            redisUtil.set(cacheKey, result, ARTICLE_LIST_CACHE_SECONDS);
        }
        
        return result;
    }

    /**
     * 构建文章数据传输对象
     * 
     * @param article 文章实体
     * @return 文章DTO对象
     */
    private ArticleDTO buildArticleVO(Article article) {
        ArticleDTO dto = new ArticleDTO();
        dto.setId(article.getId());
        dto.setContent(article.getContent());
        dto.setStatus(article.getStatus());
        dto.setViews(article.getViews());
        dto.setLikes(article.getLikes());
        dto.setCreateTime(article.getCreateTime());
        dto.setUpdateTime(article.getUpdateTime());
        
        // 获取用户信息
        User user = userMapper.selectUserById(article.getUserId());
        if (user != null) {
            dto.setAuthor(user);
        }
        
        // 获取文章媒体列表
        List<ArticleMedia> mediaList = articleMediaMapper.selectMediaByArticleId(article.getId());
        dto.setMediaList(mediaList);
        
        // 设置评论数量 - 使用缓存方法获取
        dto.setCommentCount(articleCommentService.countCommentsByArticleId(article.getId()));
        
        return dto;
    }

    /**
     * 点赞文章
     *
     * @param id     文章ID
     * @param userId 用户ID
     * @return 最新点赞数
     */
    @Transactional
    public int likeArticle(Integer id, Integer userId) {
        int likeCount = articleLikeService.likeArticle(id, userId);
        
        // 更新缓存
        clearArticleCache(id, null);
        
        return likeCount;
    }

    /**
     * 取消点赞
     *
     * @param id     文章ID
     * @param userId 用户ID
     * @return 最新点赞数
     */
    @Transactional
    public int unlikeArticle(Integer id, Integer userId) {
        int likeCount = articleLikeService.unlikeArticle(id, userId);
        
        // 更新缓存
        clearArticleCache(id, null);
        
        return likeCount;
    }

    /**
     * 分页获取文章列表
     *
     * @param pageNum  当前页码
     * @param pageSize 每页显示条数
     * @param userId   用户ID，可选
     * @param status   状态，可选
     * @return 包含分页结果的 Map
     */
    public Map<String, Object> getArticlesWithPagination(int pageNum, int pageSize, Integer userId, String status) {
        // 构建缓存键
        String cacheKey = generateArticleListCacheKey(pageNum, pageSize, userId, status);
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (Map<String, Object>) cached;
        }
        
        // 缓存未命中，查询数据库
        PageHelper.startPage(pageNum, pageSize);
        List<Article> articles = articleMapper.selectArticlesWithPagination(userId, status);
        
        // 转换为DTO对象
        List<ArticleDTO> articleDTOList = new ArrayList<>();
        for (Article article : articles) {
            articleDTOList.add(buildArticleVO(article));
        }
        
        PageInfo<Article> pageInfo = new PageInfo<>(articles);
        
        Map<String, Object> result = new HashMap<>();
        result.put("list", articleDTOList);
        result.put("total", pageInfo.getTotal());
        result.put("pages", pageInfo.getPages());
        result.put("pageNum", pageInfo.getPageNum());
        result.put("pageSize", pageInfo.getPageSize());
        
        // 将结果存入缓存
        redisUtil.set(cacheKey, result, ARTICLE_LIST_CACHE_SECONDS);
        
        return result;
    }

    /**
     * 获取用户的所有文章
     *
     * @param userId 用户ID
     * @return 文章列表
     */
    public List<ArticleDTO> getUserArticles(Integer userId) {
        if (userId == null) {
            throw new ArticleException("用户ID不能为空");
        }
        
        // 构建缓存键
        String cacheKey = ARTICLE_USER_KEY + userId;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (List<ArticleDTO>) cached;
        }
        
        // 缓存未命中，查询数据库
        List<Article> articles = articleMapper.selectArticlesByUserId(userId);
        List<ArticleDTO> articleDTOList = new ArrayList<>();
        
        for (Article article : articles) {
            articleDTOList.add(buildArticleVO(article));
        }
        
        // 将结果存入缓存
        if (!articleDTOList.isEmpty()) {
            redisUtil.set(cacheKey, articleDTOList, ARTICLE_LIST_CACHE_SECONDS);
        }
        
        return articleDTOList;
    }

    /**
     * 获取热门文章
     *
     * @param limit 限制数量
     * @return 文章列表
     */
    public List<ArticleDTO> getHotArticles(Integer limit) {
        // 构建缓存键
        String cacheKey = ARTICLE_HOT_KEY + ":" + (limit == null ? "default" : limit);
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (List<ArticleDTO>) cached;
        }
        
        // 缓存未命中，查询数据库
        int defaultLimit = 10;
        if (limit != null && limit > 0) {
            defaultLimit = limit;
        }
        
        List<Article> articles = articleMapper.selectHotArticles(defaultLimit);
        List<ArticleDTO> articleDTOList = new ArrayList<>();
        
        for (Article article : articles) {
            articleDTOList.add(buildArticleVO(article));
        }
        
        // 将结果存入缓存
        if (!articleDTOList.isEmpty()) {
            redisUtil.set(cacheKey, articleDTOList, ARTICLE_HOT_CACHE_SECONDS);
        }
        
        return articleDTOList;
    }

    /**
     * 按状态获取文章
     *
     * @param status 状态
     * @return 文章列表
     */
    public List<ArticleDTO> getArticlesByStatus(String status) {
        if (StrUtil.isBlank(status)) {
            throw new ArticleException("状态不能为空");
        }
        
        // 构建缓存键
        String cacheKey = ARTICLE_STATUS_KEY + status;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (List<ArticleDTO>) cached;
        }
        
        // 缓存未命中，查询数据库
        List<Article> articles = articleMapper.selectArticlesByStatus(status);
        List<ArticleDTO> articleDTOList = new ArrayList<>();
        
        for (Article article : articles) {
            articleDTOList.add(buildArticleVO(article));
        }
        
        // 将结果存入缓存
        if (!articleDTOList.isEmpty()) {
            redisUtil.set(cacheKey, articleDTOList, ARTICLE_LIST_CACHE_SECONDS);
        }
        
        return articleDTOList;
    }

    /**
     * 检查用户是否点赞了文章
     *
     * @param articleId 文章ID
     * @param userId    用户ID
     * @return 是否点赞
     */
    public boolean checkUserLiked(Integer articleId, Integer userId) {
        if (articleId == null) {
            throw new ArticleException("文章ID不能为空");
        }
        
        if (userId == null) {
            return false;
        }
        
        return articleLikeService.hasUserLikedArticle(articleId, userId);
    }

    /**
     * 获取文章详情及用户点赞状态
     *
     * @param id     文章ID
     * @param userId 用户ID
     * @return 包含文章详情和点赞状态的 Map
     */
    public Map<String, Object> getArticleDetailWithLikeStatus(Integer id, Integer userId) {
        ArticleDTO article = getArticleDetail(id);
        if (article == null) {
            throw new ArticleException("文章不存在");
        }
        
        boolean liked = false;
        if (userId != null) {
            liked = checkUserLiked(id, userId);
        }
        
        Map<String, Object> result = new HashMap<>();
        result.put("article", article);
        result.put("liked", liked);
        
        return result;
    }

    /**
     * 批量获取文章详情及用户点赞状态
     *
     * @param ids     文章ID列表
     * @param userId  用户ID
     * @return 包含文章ID到其详情和点赞状态映射的Map
     */
    public Map<Integer, Map<String, Object>> getBatchArticleDetailsWithLikeStatus(List<Integer> ids, Integer userId) {
        if (ids == null || ids.isEmpty()) {
            return new HashMap<>();
        }
        
        // 构建缓存键，包含用户ID以区分不同用户的点赞状态
        String userIdStr = userId == null ? "anonymous" : userId.toString();
        String idsStr = ids.stream()
                .sorted()
                .map(String::valueOf)
                .collect(Collectors.joining("-"));
        String cacheKey = ARTICLE_BATCH_KEY + "withlike:" + userIdStr + ":" + idsStr.hashCode();
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (Map<Integer, Map<String, Object>>) cached;
        }
        
        // 缓存未命中，查询文章详情
        Map<Integer, ArticleDTO> articlesMap = getBatchArticleDetails(ids);
        
        // 获取点赞状态
        List<Integer> likedArticleIds = new ArrayList<>();
        if (userId != null) {
            likedArticleIds = articleLikeService.getUserLikedArticleIds(userId, ids);
        }
        
        // 构建结果
        Map<Integer, Map<String, Object>> result = new HashMap<>();
        for (Map.Entry<Integer, ArticleDTO> entry : articlesMap.entrySet()) {
            Integer articleId = entry.getKey();
            ArticleDTO article = entry.getValue();
            
            Map<String, Object> articleWithLike = new HashMap<>();
            articleWithLike.put("article", article);
            articleWithLike.put("liked", likedArticleIds.contains(articleId));
            
            result.put(articleId, articleWithLike);
        }
        
        // 将结果存入缓存
        if (!result.isEmpty()) {
            redisUtil.set(cacheKey, result, ARTICLE_LIST_CACHE_SECONDS);
        }
        
        return result;
    }

    /**
     * 递增文章热度
     *
     * @param id 文章ID
     */
    private void incrementArticleHot(Integer id) {
        // 热度增长不应影响用户体验，可以采用异步方式
        // 这里简单地直接更新数据库，将热度等同于浏览次数
        articleMapper.incrementViews(id);
        
        // 更新文章详情缓存会在下次查询时自动刷新
        // 但需要清除热门文章列表缓存
        redisUtil.deleteByPattern(ARTICLE_HOT_KEY + "*");
    }

    /**
     * 清除文章相关缓存
     */
    private void clearArticleCache(Integer id, Integer userId) {
        if (id != null) {
            // 清除文章详情缓存
            redisUtil.delete(ARTICLE_DETAIL_KEY + id);
            // 清除批量文章详情缓存
            redisUtil.deleteByPattern(ARTICLE_BATCH_KEY + "*");
        }
        
        if (userId != null) {
            // 清除用户文章列表缓存
            redisUtil.delete(ARTICLE_USER_KEY + userId);
        }
        
        // 清除文章列表缓存
        clearArticleListCache();
        
        // 清除热门文章缓存
        redisUtil.deleteByPattern(ARTICLE_HOT_KEY + "*");
        
        // 清除状态文章缓存
        redisUtil.deleteByPattern(ARTICLE_STATUS_KEY + "*");
    }

    /**
     * 清除文章列表相关缓存
     */
    private void clearArticleListCache() {
        // 清除文章列表分页缓存
        redisUtil.deleteByPattern(ARTICLE_LIST_KEY + "*");
    }

    /**
     * 生成文章列表缓存键
     */
    private String generateArticleListCacheKey(int pageNum, int pageSize, Integer userId, String status) {
        StringBuilder keyBuilder = new StringBuilder(ARTICLE_LIST_KEY);
        keyBuilder.append(":").append(pageNum).append(":").append(pageSize);
        
        if (userId != null) {
            keyBuilder.append(":u").append(userId);
        }
        
        if (status != null) {
            keyBuilder.append(":s").append(status);
        }
        
        return keyBuilder.toString();
    }
} 